package org.totoro.time;

import org.junit.Test;

import java.time.*;
import java.time.chrono.ChronoLocalDate;
import java.time.chrono.IsoChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.ResolverStyle;
import java.time.format.SignStyle;
import java.time.temporal.*;
import java.util.Date;

import static java.time.temporal.ChronoField.DAY_OF_WEEK;

/**
 * Instant——它代表的是时间戳
 * LocalDate——不包含具体时间的日期，比如2014-01-14。它可以用来存储生日，周年纪念日，入职日期等。
 * LocalTime——它代表的是不含日期的时间
 * LocalDateTime——它包含了日期及时间，不过还是没有偏移信息或者说时区。
 * ZonedDateTime——这是一个包含时区的完整的日期时间，偏移量是以UTC/格林威治时间为基准的。
 *
 * @author daocr
 * @date 2019-08-06
 */
public class TimeTest {


    /**
     * 创建 LocalDate 年月日
     *
     * @see LocalDate#now()
     * @see LocalDate#now(Clock)
     * @see LocalDate#now(ZoneId)
     * @see LocalDate#of(int, int, int)
     */
    @Test
    public void createLocalDate() {

        LocalDate today = LocalDate.now();
        System.out.println(" 显示时间是 : " + today);

        int year = today.getYear();
        int month = today.getMonthValue();
        int day = today.getDayOfMonth();
        System.out.printf("%d:年 %d:月 %d:日 \t %n", year, month, day);


        //指定日期
        LocalDate dateOfBirth = LocalDate.of(2010, 01, 14);
        System.out.println("指定日期是 : " + dateOfBirth);

    }

    /**
     * 日期比较
     *
     * @see LocalDate#equals(Object)
     * @see LocalDate#isAfter(ChronoLocalDate)
     * @see LocalDate#isBefore(ChronoLocalDate)
     */
    @Test
    public void diffLocalDate() {

        LocalDate today = LocalDate.now();
        LocalDate dateOfBirth = LocalDate.of(2010, 01, 14);

        if (!today.equals(dateOfBirth)) {
            System.out.println("today != dateOfBirth");
        }

        if (dateOfBirth.isBefore(today)) {
            System.out.println("dateOfBirth < today");
        }

        if (today.isAfter(dateOfBirth)) {
            System.out.println("dateOfBirth > today");
        }
    }

    /**
     * 计算时间
     * <p>
     * 减法
     *
     * @see LocalDate#minus(TemporalAmount)
     * @see LocalDate#minus(long, TemporalUnit)
     * @see LocalDate#minusDays(long)
     * @see LocalDate#minusWeeks(long)
     * @see LocalDate#minusMonths(long)
     * @see LocalDate#minusYears(long)
     * <p>
     * 加法
     * @see LocalDate#plus(TemporalAmount)
     * @see LocalDate#plus(long, TemporalUnit)
     * @see LocalDate#plusDays(long)
     * @see LocalDate#plusWeeks(long)
     * @see LocalDate#plusMonths(long)
     * @see LocalDate#plusYears(long)
     * <p>
     * 只能计算同月的天数、同年的月数，不能计算隔月的天数以及隔年的月数
     * @see Period#between(LocalDate, LocalDate)
     * <p>
     * 该月有多少天
     * @see YearMonth#lengthOfMonth()
     * 该年有多少天
     * @see YearMonth#lengthOfYear()
     * 是否是闰年
     * @see YearMonth#isLeapYear()
     */
    @Test
    public void calculationLocalDate() {

        LocalDate today = LocalDate.now();
        System.out.println("今天时间:" + today);
        System.out.println("昨天时间:" + today.minus(1, ChronoUnit.DAYS));
        System.out.println("明天时间:" + today.plus(1, ChronoUnit.DAYS));


        System.out.println("---------------");

        System.out.println("今天时间:" + today);
        System.out.println("昨天时间:" + today.minus(Period.ofDays(1)));
        System.out.println("明天时间:" + today.plus(Period.ofDays(1)));


        System.out.println("\n\n");

        // 2019-8-1 日
        //只能计算同月的天数、同年的月数，不能计算隔月的天数以及隔年的月数
        LocalDate java8Release = LocalDate.of(2019, 8, 1);
        Period periodToNextJavaRelease = Period.between(java8Release, today);
        System.out.println("相差日:" + periodToNextJavaRelease.getDays() + "  ps :只能计算同月的天数、同年的月数，不能计算隔月的天数以及隔年的月数");

        System.out.println("\n\n");

        YearMonth yearMonth = YearMonth.of(2019, 2);
        System.out.println("2019 年 2月  共:" + yearMonth.lengthOfMonth() + "天");
        System.out.println("2019 年 共:" + yearMonth.lengthOfYear() + "天");

    }


    /**
     * 创建 createLocalTime 时分秒
     *
     * @see LocalTime#now()
     * @see LocalTime#of(int, int)
     * @see LocalTime#of(int, int, int)
     * @see LocalTime#of(int, int, int, int)
     */
    @Test
    public void createLocalTime() {
        LocalTime time = LocalTime.now();
        System.out.println("现在时间是: " + time);
        System.out.println("指定时间是:" + LocalTime.of(6, 10));
    }

    /**
     * 计算时间
     * <p>
     * 减法
     *
     * @see LocalTime#minus(TemporalAmount)
     * @see LocalTime#minus(long, TemporalUnit)
     * @see LocalTime#minusNanos(long)
     * @see LocalTime#minusSeconds(long)
     * @see LocalTime#minusMinutes(long) (long)
     * @see LocalTime#minusHours(long) (long)
     * <p>
     * 加法
     * @see LocalTime#plus(TemporalAmount)
     * @see LocalTime#plus(long, TemporalUnit)
     * @see LocalTime#plusNanos(long) (long)
     * @see LocalTime#plusSeconds(long) (long)
     * @see LocalTime#plusMinutes(long) (long)
     * @see LocalTime#plusHours(long) (long)
     */
    @Test
    public void calculationLocalTime() {

        LocalTime today = LocalTime.now();

        System.out.println("今天时间:" + today);
        System.out.println("前一小时时间:" + today.minus(1, ChronoUnit.HOURS));
        System.out.println("后一小时时间:" + today.plus(1, ChronoUnit.HOURS));

        System.out.println("---------------");

        System.out.println("今天时间:" + today);
        System.out.println("前一小时时间:" + today.minus(Duration.ofHours(1)));
        System.out.println("后一小时时间:" + today.plus(Duration.ofHours(1)));


    }

    /**
     * 创建 LocalDateTime 年月日 时分秒
     *
     * @see LocalDateTime#now()
     * @see LocalDateTime#now(Clock)
     * @see LocalDateTime#now(ZoneId)
     */
    @Test
    public void createLocalDateTime() {

        System.out.println("默认时间:" + LocalDateTime.now());

        // 当前时间,对应的其他时区时间
        Clock fixed = Clock.fixed(Instant.now(), ZoneId.of("America/New_York"));
        System.out.println("纽约时间:" + LocalDateTime.now(fixed));

        // 当前时区指定为纽约时间
        System.out.println("纽约时间:" + ZonedDateTime.of(LocalDateTime.now(), ZoneId.of("America/New_York")));


        ZoneOffset offset = ZoneOffset.of("-12:00");
        System.out.println(OffsetDateTime.of(LocalDateTime.now(), offset));

    }

    /**
     * 创建 时间戳
     */
    @Test
    public void createInstant() {

        Instant now = Instant.now();

        System.out.println("现在时间是:" + now);
    }


    @Test
    public void api() {

        LocalDate start = LocalDate.of(2019, 4, 29);
        LocalDate end = LocalDate.of(2019, 7, 29);


        do {

            System.out.println(start + "     start.toEpochDay():" + start.toEpochDay() + "   end.toEpochDay()" + end.toEpochDay());
            start = start.plusDays(1);


        } while (start.toEpochDay() <= end.toEpochDay());
    }

    /**
     * 时间 格式化
     */
    @Test
    public void format() {

        String format = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));

        String format2 = LocalDate.now().format(DateTimeFormatter.ISO_DATE);

        System.out.println(format);

        System.out.println(format2);


    }

    /**
     * 周期 策略
     */
    @Test
    public void temporalAdjusters() {

        LocalDate now = LocalDate.now();

        // 下周一
        System.out.println(now.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).format(DateTimeFormatter.ISO_DATE));

        // 本月第一天
        System.out.println(now.with(TemporalAdjusters.firstDayOfMonth()).format(DateTimeFormatter.ISO_DATE));

        // 本月最后一天
        System.out.println(now.with(TemporalAdjusters.lastDayOfMonth()).format(DateTimeFormatter.ISO_WEEK_DATE));

        // 本年第一天
        System.out.println(now.with(TemporalAdjusters.firstDayOfNextYear()).format(DateTimeFormatter.ISO_DATE));

        // 本年最后一天
        System.out.println(now.with(TemporalAdjusters.lastDayOfYear()).format(DateTimeFormatter.ISO_DATE));

    }

    /**
     * 周计算
     *
     * </pre>
     */
    @Test
    public void week() {

        //1、 2020 年，第一周
        String text = "2020-1";

        //每周开始时间是礼拜一
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYY-w E");
        System.out.println(LocalDate.parse(text + " 星期一", formatter).format(DateTimeFormatter.ISO_DATE));

        // 2、ISO8601 标准
        // 2020 年 第一周的礼拜二
        LocalDate parse = LocalDate.parse("2020-W01-2", DateTimeFormatter.ISO_WEEK_DATE);

        System.out.println(parse.format(DateTimeFormatter.ISO_DATE));

        String format = LocalDate.parse("2019-12-30").format(DateTimeFormatter.ISO_WEEK_DATE);

        System.out.println(format);

        WeekFields.of(DayOfWeek.MONDAY, 3);


    }

    /**
     * 自定义周计算逻辑
     * <pre>
     *     模式	    一周的第一天              范围
     *      0	        星期日               0-53
     *      1	        星期一	            0-53
     *      2	        星期日	            1-53
     *      3	        星期一	            1-53
     *      4	        星期日	            0-53
     *      5	        星期一	            0-53
     *      6	        星期日	            1-53
     *      7	        星期一	            1-53
     *
     * 上表中“今年有4天以上”表示：
     *
     * 如果星期包含1月1日，并且在新的一年中有4天或更多天，那么这周是第1周。
     * 否则，这一周的数字是前一年的最后一周，下周是第1周。
     */
    @Test
    public void customizeWeek() {


        TemporalField weekFields = WeekFields.ISO.weekOfYear();
        int firstWeek = LocalDate.of(2018, 1, 1).get(weekFields);
        int lastWeek = LocalDate.of(2018, 12, 31).get(weekFields);
        System.out.println("2018 年第一周：" + firstWeek + " 最后一周：" + lastWeek);

        // ** 计算 week 差值

        LocalDateTime currentLocalDateTime = LocalDateTime.of(2019, 12, 16, 0, 0, 0);
        LocalDateTime staticLocalDateTime = LocalDateTime.of(1900, 1, 1, 0, 0, 0);
        //计算日期最佳方式
        //以下两种计算方式等价
        System.out.println(ChronoUnit.WEEKS.between(staticLocalDateTime, currentLocalDateTime) + 1);
        System.out.println(staticLocalDateTime.until(currentLocalDateTime, ChronoUnit.WEEKS) + 1);


    }


    //MonthDay
    //YearMonth
    //Clock


}
